#include "copyright.h"
#include "system.h"
#include <iostream>


void ShortestLineTest()
{
	std::cout<<"Running test for shortest line"<<std::endl;
	ticketClerkLineLock=new Lock("ticket clerk line lock");	//Initialize the ticketClerkLineLock
	int numberOfClerks = 5;

	//Make the clerks, but don't start them
	for(int i = numberOfClerks-1; i >= 0; i--)
	{
		ticketClerkThreads[i] = new Thread("ticketClerkThread "+i);
		ticketClerkConditionVariables[i] = new Condition("ticketClerkCondition "+i);
		ticketClerkLineConditionVariables[i] = new Condition("ticketClerkLineCondition");
		ticketClerkLocks[i] = new Lock("Ticket Clerk Lock "+i);
		ticketClerkLineCount[i] = 0;
		ticketEarnings[i]=0;
		ticketClerkState[i] = busy; //Make them busy so they get a line
	}
	
	//Make 9 Customers
	Thread *testCustomerThread;
	for(int i = 0; i<9;i++)
	{
		testCustomerThread = new Thread("Test Customer");
		testCustomerThread->Fork((VoidFunctionPtr)CustomerAgent,0);
	}
	

	//Wait for all 9 customers to be in line
	int inLine = 0;
	while(inLine <9)
	{
		inLine = 0;
		for(int i=0; i<5; i++)
		{
			inLine+=ticketClerkLineCount[i];
		}
		currentThread->Yield();
	}

	//Show that line fullness is 2 2 2 2 1
	for(int i=0; i<5; i++)
	{
			std::cout<<"Ticket Clerk #"<<i<<" Line Size ="<<ticketClerkLineCount[i]<<std::endl;
	}

	//Add More Customers
	
	for(int i = 0; i<2;i++)
	{
		testCustomerThread = new Thread("Test Customer");
		testCustomerThread->Fork((VoidFunctionPtr)CustomerAgent,0);
	}
	
	//Wait for these customers to enter
	while(inLine <11)
	{
		inLine = 0;
		for(int i=0; i<5; i++)
		{
			inLine+=ticketClerkLineCount[i];
		}
		currentThread->Yield();
	}

	//Show that the new line fullness is 3 2 2 2 2
	//This means that one of the new customers filling in the smallest line, and the second picked the first line he found because they were all the same size
	for(int i=0; i<5; i++)
	{
			std::cout<<"Ticket Clerk #"<<i<<" Line Size ="<<ticketClerkLineCount[i]<<std::endl;
	}


	std::cout<<"End\n";
	
}

void Manager_ClerkBreaks() {
	std::cout<<"\n\nRunning test to see if manager takes clerks off of break"<<std::endl;
	THEATER_TESTS = 1;	/*enables the manager to stop itself since this is just a test*/

	/*make ticket clerks, don't start them*/
	ticketClerkLineLock = new Lock("test ticketClerkLineLock");
	ticketClerks = 5;

	for(int i = 0; i < ticketClerks-1; i++) {
		ticketClerkThreads[i] = new Thread("ticketClerkThread "+i);
		ticketClerkLineConditionVariables[i] = new Condition("ticketClerkLineCondition");
		ticketClerkLocks[i] = new Lock("Ticket Clerk Lock "+i);
		ticketClerkState[i] = busy; //Make them busy so they get a line
		ticketClerkLineCount[i] = 6;	/*put six customers in each line but one*/
		ticketClerkConditionVariables[i] = new Condition("test ticketClerkConditionVariable" + i);
	}
	ticketClerkThreads[ticketClerks-1] = new Thread("ticketClerkThread " + ticketClerks-1);
	ticketClerkLineConditionVariables[ticketClerks-1] = new Condition("ticketClerkLineCondition");
	ticketClerkLocks[ticketClerks-1] = new Lock("Ticket Clerk Lock "+ ticketClerks-1);
	ticketClerkState[ticketClerks-1] = on_break; //put one on break
	ticketClerkLineCount[ticketClerks-1] = 0;	/*put six customers in each line but one*/
	ticketClerkConditionVariables[ticketClerks-1] = new Condition("test ticketClerkConditionVariable" + ticketClerks-1);

	
	startMovieConditionVariable = new Condition("test Start Movie CV");

	/*make sure manager doesn't start a movie*/
	movieStarted = true;

	/*set up extra data for ticket clerk interaction*/
	numberOfCustomers = 6;
	
	/*expect: busy busy busy busy on_break*/
	printf("Original ticket clerk states:\n");
	for(int i = 0; i < ticketClerks; i++) {
		if(ticketClerkState[i] == 0) {
			printf("available\t");
		}
		else if(ticketClerkState[i] == 1) {
			printf("busy\t");
		}
		else if(ticketClerkState[i] == 2) {
			printf("on_break\t");
		}
		else if(ticketClerkState[i] == 3) {
			printf("no_clerk\t");
		}
	}
	printf("\nEach Clerk is busy and the last one should be on break\n");
	

	/*start the manager thread*/
	managerClerkGoingOnBreakConditionVariable = new Condition("Manager Break Condition");
	managerLock = new Lock("Manager Lock");
	Thread *testManager = new Thread("Test Manager");
	testManager->Fork((VoidFunctionPtr)Manager, 0);

	while(ticketClerkState[ticketClerks-1] == on_break) {
		currentThread->Yield();
	}
	
	/*expect: busy busy busy busy available*/
	printf("New ticket clerk states:\n");
	for(int i = 0; i < ticketClerks; i++) {
		if(ticketClerkState[i] == 0) {
			printf("available\t");
		}
		else if(ticketClerkState[i] == 1) {
			printf("busy\t");
		}
		else if(ticketClerkState[i] == 2) {
			printf("on_break\t");
		}
		else if(ticketClerkState[i] == 3) {
			printf("no_clerk\t");
		}
	}
	printf("\nNow the clerk that was on break should be available\n");

}

void Manager_CheckMoney() {
	std::cout<<"\n\nRunning test to see if manager reads money from clerks one at a time"<<std::endl;
	THEATER_TESTS = 2;	/*enables the manager to stop itself and immediately output since this is just a test*/

	/*make ticket clerks, don't start them*/
	ticketClerks = 5;
	for(int i = 0; i < ticketClerks; i++) {
		ticketClerkThreads[i] = new Thread("test ticketClerkThread "+i);
		ticketClerkLocks[i] = new Lock("test Ticket Clerk Lock "+i);
		ticketEarnings[i] = i * 10;	/*give each clerk a random amount*/
	}

	/*make food clerks, don't start them*/
	foodClerks = 5;
	for(int i = 0; i < foodClerks; i++) {
		foodClerkThreads[i] = new Thread("test foodClerkThread "+i);
		foodClerkLocks[i] = new Lock("test Food Clerk Lock "+i);
		foodEarnings[i] = i * 5;	/*give each clerk a random amount*/
	}
	

	/*start the manager thread*/
	managerLock = new Lock("test Manager Lock");
	Thread *testManager = new Thread("testManager");
	testManager->Fork((VoidFunctionPtr)Manager, 0);
}

void TheaterTestSuite()
{
	THEATER_TESTS = true;
	ShortestLineTest();
	Manager_ClerkBreaks();
	Manager_CheckMoney();
}
